﻿// author : David Janacek, dj-soft@seznam.cz, 2013-12-13
// company: Asseco Solution, a.s. CZ
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using Noris.LCS.AIDCCodes.Common;

namespace Noris.LCS.AIDCCodes
{
    /// <summary>
    /// 
    /// </summary>
    public class CodeManager
    {
        #region EncodeToFile
        public static string EncodeToFile(string content, string codeName, int width, int height, string targetFile)
        {
            CodeProperties properties = new CodeProperties() { Content = content, CodeName = codeName, ImageWidth = width, ImageHeight = height };
            return _EncodeToFile(properties, targetFile);
        }
        public static string EncodeToFile(string content, CodeType codeType, int width, int height, string targetFile)
        {
            CodeProperties properties = new CodeProperties() { Content = content, CodeType = codeType, ImageWidth = width, ImageHeight = height };
            return _EncodeToFile(properties, targetFile);
        }
        public static string EncodeToFile(string content, string codeName, int moduleSize, string targetFile)
        {
            CodeProperties properties = new CodeProperties() { Content = content, CodeName = codeName, ModuleSize = moduleSize };
            return _EncodeToFile(properties, targetFile);
        }
        public static string EncodeToFile(string content, CodeType codeType, int moduleSize, string targetFile)
        {
            CodeProperties properties = new CodeProperties() { Content = content, CodeType = codeType, ModuleSize = moduleSize };
            return _EncodeToFile(properties, targetFile);
        }
        public static string EncodeToFile(CodeProperties properties, string targetFile)
        {
            return _EncodeToFile(properties, targetFile);
        }
        private static string _EncodeToFile(CodeProperties properties, string targetFile)
        {
            string result = null;
            try
            {
                _CreatePathForFile(targetFile);
                CodeType ct = _GetCodeType(properties);
                using (CodeMatrix matrix = CodeEncoder.Encode(properties.Content, ct))
                {
                    using (Bitmap bitmap = matrix.ToBitmap(properties))
                    {
                        System.Drawing.Imaging.ImageFormat format = CodeMatrix.GetImageFormatFromName(targetFile);
                        bitmap.Save(targetFile, format);
                    }
                }
            }
            catch (Exception exc)
            {
                result = exc.Message;
            }
            return result;
        }
        /// <summary>
        /// Create a directory for file
        /// </summary>
        /// <param name="targetFile"></param>
        private static void _CreatePathForFile(string targetFile)
        {
            if (String.IsNullOrEmpty(targetFile))
                throw new ArgumentNullException("targetFile", "Argument \"targetFile\" can not be empty string.");

            System.IO.FileInfo fi = new System.IO.FileInfo(targetFile);
            System.IO.DirectoryInfo di = fi.Directory;
            di.Refresh();
            if (!di.Exists)
                di.Create();
        }
        /// <summary>
        /// Return CodeType for code (from codeType or codeName)
        /// </summary>
        /// <param name="codeType"></param>
        /// <param name="codeName"></param>
        /// <returns></returns>
        private static CodeType _GetCodeType(CodeProperties properties)
        {
            if (properties.CodeType.HasValue) return properties.CodeType.Value;
            return Common.CodeEncoder.GetCodeType(properties.CodeName, null);
        }
        #endregion
        #region EncodeToBitmap
        /// <summary>
        /// Return a bitmap for Bar or QR code.
        /// </summary>
        /// <param name="content">Text content of code</param>
        /// <param name="codeName"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static Bitmap EncodeToBitmap(string content, string codeName, int width, int height)
        {
            CodeProperties properties = new CodeProperties() { Content = content, CodeName = codeName, ImageWidth = width, ImageHeight = height };
            return _EncodeToBitmap(properties);
        }
        /// <summary>
        /// Return a bitmap for Bar or QR code.
        /// </summary>
        /// <param name="content">Text content of code</param>
        /// <param name="codeType"></param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <returns></returns>
        public static Bitmap EncodeToBitmap(string content, CodeType codeType, int width, int height)
        {
            CodeProperties properties = new CodeProperties() { Content = content, CodeType = codeType, ImageWidth = width, ImageHeight = height };
            return _EncodeToBitmap(properties);
        }
        /// <summary>
        /// Return a bitmap for Bar or QR code.
        /// </summary>
        /// <param name="content">Text content of code</param>
        /// <param name="codeName"></param>
        /// <param name="moduleSize"></param>
        /// <returns></returns>
        public static Bitmap EncodeToBitmap(string content, string codeName, int moduleSize)
        {
            CodeProperties properties = new CodeProperties() { Content = content, CodeName = codeName, ModuleSize = moduleSize };
            return _EncodeToBitmap(properties);
        }
        /// <summary>
        /// Return a bitmap for Bar or QR code.
        /// </summary>
        /// <param name="content">Text content of code</param>
        /// <param name="codeType"></param>
        /// <param name="moduleSize"></param>
        /// <returns></returns>
        public static Bitmap EncodeToBitmap(string content, CodeType codeType, int moduleSize)
        {
            CodeProperties properties = new CodeProperties() { Content = content, CodeType = codeType, ModuleSize = moduleSize };
            return _EncodeToBitmap(properties);
        }
        /// <summary>
        /// Return a bitmap for Bar or QR code.
        /// </summary>
        /// <param name="properties">Text content and other properties of code</param>
        /// <returns></returns>
        public static Bitmap EncodeToBitmap(CodeProperties properties)
        {
            return _EncodeToBitmap(properties);
        }
        private static Bitmap _EncodeToBitmap(CodeProperties properties)
        {
            Bitmap bitmap = null;
            CodeType ct = _GetCodeType(properties);
            using (CodeMatrix matrix = CodeEncoder.Encode(properties.Content, ct))
            {
                bitmap = matrix.ToBitmap(properties);
            }
            return bitmap;
        }
        #endregion
        #region CanEncode
        /// <summary>
        /// Return true when specified code can be encoded (exists appropriate encoder).
        /// When code name is not recognized, return false.
        /// </summary>
        /// <param name="codeName"></param>
        /// <returns></returns>
        internal static bool CanEncode(string codeName)
        {
            return Common.CodeEncoder.CanEncode(codeName);
        }
        /// <summary>
        /// Return true when specified code type can be encoded (exists appropriate encoder).
        /// </summary>
        /// <param name="codeType"></param>
        /// <returns></returns>
        internal static bool CanEncode(CodeType codeType)
        {
            return Common.CodeEncoder.CanEncode(codeType);
        }
        #endregion
    }
    #region class CodeProperties
    /// <summary>
    /// Descriptions for prepare image of code
    /// </summary>
    public class CodeProperties
    {
        public CodeProperties()
        {
            this.Content = null;
            this.CodeType = null;
            this.CodeName = null;
            this.Resolution = 300;
            this.GrayColor = Color.White;
            this.WhiteColor = Color.White;
            this.BlackColor = Color.Black;
            this.LabelColor = Color.Black;
            this.LabelVisible = true;
            this.Orientation = CodeOrientation.Regular;
        }
        /// <summary>
        /// Text content of code
        /// </summary>
        public string Content { get; set; }
        /// <summary>
        /// Type of code (or set name of CodeType into CodeName)
        /// </summary>
        public CodeType? CodeType { get; set; }
        /// <summary>
        /// Name of code type
        /// </summary>
        public string CodeName { get; set; }
        /// <summary>
        /// Size of logical point of code, in pixel. 
        /// If size of image is defined in ImageWidth and ImageHeight, then ModuleSize is ignored.
        /// If size does not defined (ImageWidth, ImageHeight and ModuleSize is null), then default ModuleSize = 8 will be used.
        /// </summary>
        public Int32? ModuleSize { get; set; }
        /// <summary>
        /// Width of image in pixel. Code will be fitted into.
        /// If is null (or zero or negative), then ModuleSize will be used (or default ModuleSize = 8).
        /// </summary>
        public Int32? ImageWidth { get; set; }
        /// <summary>
        /// Height of image in pixel. Code will be fitted into.
        /// If is null (or zero or negative), then ModuleSize will be used (or default ModuleSize = 8).
        /// </summary>
        public Int32? ImageHeight { get; set; }
        /// <summary>
        /// Resolution of image [DPI], default = 300dpi.
        /// </summary>
        public Int32 Resolution { get; set; }
        /// <summary>
        /// Color of background of image, where does not code placed.
        /// Default = White.
        /// </summary>
        public Color GrayColor { get; set; }
        /// <summary>
        /// Color of white area of code.
        /// Default = White.
        /// </summary>
        public Color WhiteColor { get; set; }
        /// <summary>
        /// Color of black area of code.
        /// Default = Black.
        /// </summary>
        public Color BlackColor { get; set; }
        /// <summary>
        /// Color of label, if is used.
        /// Default = Black.
        /// </summary>
        public Color LabelColor { get; set; }
        /// <summary>
        /// Label of code has be drawned?
        /// </summary>
        public bool LabelVisible { get; set; }
        /// <summary>
        /// Orientation of code on image. Not tested.
        /// </summary>
        public CodeOrientation Orientation { get; set; }
    }
    #endregion
    #region enum CodeOrientation
    /// <summary>
    /// Orientation of code image
    /// </summary>
    [Flags]
    public enum CodeOrientation
    {
        /// <summary>0: standard: read from left to right, down edge of code is bottom</summary>
        Regular = 0,
        /// <summary>1: rotate of 90° counterclockwise: read from bottom to top, down edge of code is on right side</summary>
        Rotate90 = 1,
        /// <summary>2: rotate of 180°: read from right to left, down edge of code is on top side</summary>
        Rotate180 = 2,
        /// <summary>3: rotate of 90° clockwise: read from top to bottom, down edge of code is on left side</summary>
        Rotate270 = 3,
        /// <summary>4: flip horizontally: left edge of code is mirrored to right edge of image, bottom edge remainig on down side of image</summary>
        MirrorX = 4,
        /// <summary>8: flip vertically: top edge of code is mirrored to bottom edge of image, left edge remainig on left side of image</summary>
        MirrorY = 8
    }
	#endregion
    #region enum CodeType
    /// <summary>
    /// BarCode types
    /// </summary>
    public enum CodeType : int
    {
        None = 0,

        Codabar,
        Code11,
        EAN13,
        EAN8,
        UPC_A,
        UPC_E,
        Standard2of5,
        Industrial2of5,
        Interleaved2of5,
        ITF14,
        Code39,
        Code39Ext,
        Code128,
        Code128A,
        Code128B,
        Code128C,
        Pharmacode,
        /*
        UPC_Supplemental_2digit,
        UPC_Supplemental_5digit,
        JAN13,
        ISBN,
        UNSPECIFIED,
        PostNet,
        BOOKLAND,
        MSI_Mod10,
        MSI_2Mod10,
        MSI_Mod11,
        MSI_Mod11_Mod10,
        Modified_Plessey,
        USD8,
        UCC12,
        UCC13,
        LOGMARS,
        CODE93,
        TELEPEN,
        FIM,
         */
        /// <summary>QR code with default Error correction level (= Medium, 15% of codewords can be restored)</summary>
        QrCode = 0x1000,
        /// <summary>QR code with Error correction level = Low (7% of codewords can be restored)</summary>
        QrCodeLow,
        /// <summary>QR code with Error correction level = Medium (15% of codewords can be restored)</summary>
        QrCodeMedium,
        /// <summary>QR code with Error correction level = Quartile (25% of codewords can be restored)</summary>
        QrCodeQuartile,
        /// <summary>QR code with Error correction level = Hight (30% of codewords can be restored)</summary>
        QrCodeHigh
    }
    #endregion
}
